package com.snails.net.retrofit;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.snails.logger.Logger;
import com.snails.net.retrofit.converter.FastJsonConverterFactory;
import com.snails.net.retrofit.cookie.CookieManger;
import com.snails.net.retrofit.interceptor.CacheInterceptor;
import com.snails.net.retrofit.interceptor.HttpLoggingInterceptor;
import com.snails.net.retrofit.interceptor.RetryInterceptor;
import com.snails.net.retrofit.progress.ProgressManager;
import com.snails.net.utils.FileUtil;
import com.snails.net.utils.NetworkUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import okhttp3.Cache;
import okhttp3.ConnectionSpec;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.TlsVersion;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

/**
 * @author lawrence
 * <p/>
 * @link https://www.cnblogs.com/Jason-Jan/p/8010795.html
 * @link http://www.cnblogs.com/whoislcj/p/5537640.html
 * <p/>
 * 使用说明：
 * 1、建议采用单利模式使用本类
 * 2、需权限：
 * -------- 隐私权限：
 * ---------------- android.permission.WRITE_EXTERNAL_STORAGE
 * ---------------- android.permission.READ_EXTERNAL_STORAGE
 * -------- 普通权限：
 * ---------------- android.permission.INTERNET
 * ---------------- android.permission.ACCESS_WIFI_STATE
 * ---------------- android.permission.ACCESS_NETWORK_STATE
 */

public class RetrofitClient {
    public static final String DOMAIN = "Domain-Name";

    private final Retrofit mRetrofit;
    private final boolean mSupportMoreBaseUrl;
    private final CookieManger mCookie;

    // **************************************************************************
    // ===== 构造者 =====
    // **************************************************************************
    private RetrofitClient(Context ctx, final Builder builder) {
        NetworkUtil.init(ctx);  // 需要初始化NetworkUtil，缓存拦截器中有使用
        mSupportMoreBaseUrl = builder.moreBaseUrl;

        // 创建 OKHttpClient
        OkHttpClient.Builder okBuilder = new OkHttpClient.Builder();

        // 超时设置
        okBuilder.connectTimeout(builder.default_time_out, TimeUnit.SECONDS); // 连接超时时间
        okBuilder.writeTimeout(builder.default_w_time_out, TimeUnit.SECONDS); // 写操作超时时间
        okBuilder.readTimeout(builder.default_r_time_out, TimeUnit.SECONDS);  // 读操作超时时间

        // https://www.jianshu.com/p/64499bdf6842
        // https,http问题
        ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
                .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
                .allEnabledCipherSuites()
                .build();//解决在Android5.0版本以下https无法访问
        ConnectionSpec spec1 = new ConnectionSpec.Builder(ConnectionSpec.CLEARTEXT).build();//兼容http接口
        okBuilder.connectionSpecs(Arrays.asList(spec,spec1));

        if (builder.moreBaseUrl) {
            // 以最简洁的Api让Retrofit
            // 同时支持多个BaseUrl以及动态改变BaseUrl.
            RetrofitUrlManager.getInstance().with(okBuilder);
        }

        // 网络异常重试
        okBuilder.retryOnConnectionFailure(true); // 开启okHttp内置重连机制
//        okBuilder.addInterceptor(new RetryInterceptor());

        // 缓存设置
        if (builder.cache_file != null) {
            /**
             * 使用说明:
             *  ------- 请求头要添加字段 cache-json 指明缓存策略{@link UseCacheStrategy#NET_OR_CACHE}
             */
            okBuilder.cache(new Cache(builder.cache_file, builder.cache_size));
            okBuilder.addInterceptor(new CacheInterceptor());
        }

        // 文件上传下载进度监听
        // 具体使用参考：https://github.com/JessYanCoding/ProgressManager/blob/master/README-zh.md
        ProgressManager.getInstance().with(okBuilder);

        // 设置拦截器
        if (builder.interceptors != null) {
            for (int i = 0; i < builder.interceptors.size(); i++) {
                okBuilder.addInterceptor(builder.interceptors.get(i));
            }
        }

        // 设置网络-请求拦截器
        if (builder.networkInterceptors != null) {
            for (int i = 0; i < builder.networkInterceptors.size(); i++) {
                okBuilder.addNetworkInterceptor(builder.networkInterceptors.get(i));
            }
        }

        // 日志输出
        if (builder.debug) {
            HttpLoggingInterceptor logging
                    = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
                @Override
                public void log(String message) {
                    if (Logger.debug()) {
                        Log.i(builder.loggerTag + " OkHttp", message);
                        if (Logger.format()) {
                            try {
                                Thread.sleep(1);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }).setLevel(HttpLoggingInterceptor.Level.BODY);
            okBuilder.addInterceptor(logging);
        }

        // https://github.com/zhou-you/RxEasyHttp
        // cookie
        okBuilder.cookieJar(mCookie = new CookieManger(ctx.getApplicationContext()));

        // 创建Retrofit
        mRetrofit = new Retrofit.Builder()
                .client(okBuilder.build())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(ScalarsConverterFactory.create())  // 转换失败，执行后面的转接器
                .addConverterFactory(FastJsonConverterFactory.create()) // 万能，转换失败就异常
                .baseUrl(builder.base_url)
                .build();

        if (builder.moreBaseUrl) {
            // 全局 BaseUrl 的优先级低于 Domain-Name header 中单独配置的,
            // 其他未配置的接口将受全局 BaseUrl 的影响
            RetrofitUrlManager.getInstance().setGlobalDomain(builder.base_url);
        }
    }

    // 可在 App 运行时,随时切换 BaseUrl (指定了 Domain-Name header 的接口)
    public void putDomain(String name, String baseUrl) {
        if (mSupportMoreBaseUrl) {
            RetrofitUrlManager.getInstance().putDomain(name, baseUrl);
        }
    }

    /**
     * 得到cookie
     */
    public CookieManger getCookie() {
        return mCookie;
    }

    /**
     * 获取对应的Service
     *
     * @param service Service 的 class
     * @param <T>
     * @return
     */
    public <T> T create(Class<T> service) {
        return mRetrofit.create(service);
    }

    // **************************************************************************
    // ===== 配置器 =====
    // **************************************************************************
    public static class Builder {
        // 超时设置
        private int default_time_out = 30;
        private int default_r_time_out = 30;
        private int default_w_time_out = 30;
        // 网络根地址
        private String base_url = "";
        // 拦截器设置
        private List<Interceptor> interceptors = null;
        private List<Interceptor> networkInterceptors = null;
        // 缓存设置
        private long cache_size = 10 * 1024 * 1024; // 10 MiB
        private File cache_file = null;  // 缓存路径
        // 日志
        private boolean debug = true;
        private String loggerTag = "Snails-net";
        // 以最简洁的Api让Retrofit 同时支持多个BaseUrl以及动态改变BaseUrl.
        private boolean moreBaseUrl = false;

        /**
         * 连接超时时间
         *
         * @param time 单位：秒
         * @return
         */
        public Builder timeOut(int time) {
            default_time_out = time;
            return this;
        }

        /**
         * 读操作超时时间
         *
         * @param time 单位：秒
         * @return
         */
        public Builder rTimeOut(int time) {
            default_r_time_out = time;
            return this;
        }

        /**
         * 写操作超时时间
         *
         * @param time 单位：秒
         * @return
         */
        public Builder wTimeOut(int time) {
            default_w_time_out = time;
            return this;
        }

        /**
         * 设置根url
         *
         * @param url 根地址
         * @return
         */
        public Builder baseUrl(String url) {
            base_url = url;
            return this;
        }

        /**
         * 缓存设置
         *
         * @param file 缓存存放路径
         * @param size 缓存大学
         * @return
         */
        public Builder cache(File file, long size) {
            cache_file = file;
            cache_size = size;
            return this;
        }

        /**
         * 日志输出
         *
         * @param debug true-输出,false-不输出
         * @param tag   标签
         * @return
         */
        public Builder debug(boolean debug, String tag) {
            this.debug = debug;
            this.loggerTag = tag;
            return this;
        }

        /**
         * 以最简洁的Api让Retrofit
         * 同时支持多个BaseUrl以及动态改变BaseUrl.
         */
        public Builder moreBaseUrl(boolean enable) {
            this.moreBaseUrl = enable;
            return this;
        }

        /**
         * 添加拦截器，在response中调用
         *
         * @param interceptor 拦截器
         * @return
         */
        public Builder addInterceptor(Interceptor interceptor) {
            if (interceptor != null) {
                if (interceptors == null) {
                    interceptors = new ArrayList<>();
                }
                interceptors.add(interceptor);
            }
            return this;
        }

        /**
         * 添加拦截器，在response中调用
         */
        public Builder addInterceptors(List<Interceptor> interceptors) {
            if (interceptors != null && interceptors.size() > 0) {
                if (this.interceptors == null) {
                    this.interceptors = new ArrayList<>();
                }
                this.interceptors.addAll(interceptors);
            }
            return this;
        }

        /**
         * 添加网络-请求拦截器，在request和response中各调用一次
         *
         * @param interceptor 拦截器
         * @return
         */
        public Builder addNetworkInterceptor(Interceptor interceptor) {
            if (interceptor != null) {
                if (networkInterceptors == null) {
                    networkInterceptors = new ArrayList<>();
                }
                networkInterceptors.add(interceptor);
            }
            return this;
        }

        /**
         * 添加网络-请求拦截器，在request和response中各调用一次
         */
        public Builder addNetworkInterceptors(List<Interceptor> interceptors) {
            if (interceptors != null && interceptors.size() > 0) {
                if (this.networkInterceptors == null) {
                    this.networkInterceptors = new ArrayList<>();
                }
                this.networkInterceptors.addAll(interceptors);
            }
            return this;
        }

        public RetrofitClient build(Context ctx) {
            if (TextUtils.isEmpty(base_url)) {
                throw new NullPointerException("baseUrl can not be null or \"\".");
            }
            if (ctx == null) {
                throw new NullPointerException("ctx can not be null.");
            }
            if (cache_size <= 0) {
                cache_size = 10 * 1024 * 1024; // 10 MiB
            }
            if (cache_file == null) {
                cache_file = FileUtil.appCreateFolder(ctx, "JsonCache");
            }
            return new RetrofitClient(ctx.getApplicationContext(), this);
        }

    }

}
